Fix resolution with `default-features = false`
authorAlex Crichton <alex@alexcrichton.com>
Sun, 14 Jun 2015 18:16:46 +0000 (11:16 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Sun, 14 Jun 2015 18:18:55 +0000 (11:18 -0700)
There was previously a bug in resolve where turning off the default set of
features would cause resolve to not correctly settle on the set of features
activated for a package. If one dependency turned off all features, and then the
next dependency to be activated only turned on the default feature, the default
feature wouldn't actually end up getting activated.

This commit alters the check to see if the package has been previously activated
to more rigorously check to see if the 'default' feature is activated
previously. If a dependency doesn't use the default feature, or if the package
itself does not have the feature "default", then the package is considered
activated, but otherwise it needs to go through another cycle of resolution.

src/cargo/core/resolver/mod.rs
tests/support/mod.rs
tests/test_cargo_features.rs

index 2f9bd5725fdc2e10aaf35ff01677eafb38e7ae3e..a72d7a53414c3bd2d6c29785232c291a140cc20c 100644 (file)
@@ -234,12 +234,14 @@ fn flag_activated(cx: &mut Context,
         }
         Method::Everything => return false,
     };
+
+    let has_default_feature = summary.features().contains_key("default");
     match cx.resolve.features(id) {
         Some(prev) => {
             features.iter().all(|f| prev.contains(f)) &&
-                (!use_default || prev.contains("default"))
+                (!use_default || prev.contains("default") || !has_default_feature)
         }
-        None => features.len() == 0,
+        None => features.len() == 0 && (!use_default || !has_default_feature)
     }
 }
 
index fa004f25478e07c9e384a3c491642b49df8c04e3..fce7fd1997ca33683f7bec6d7f665540a1c0ac5e 100644 (file)
@@ -134,7 +134,9 @@ impl ProjectBuilder {
 
     pub fn process<T: AsRef<OsStr>>(&self, program: T) -> ProcessBuilder {
         let mut p = process(program).unwrap();
-        p.cwd(&self.root()).env("HOME", &paths::home());
+        p.cwd(&self.root())
+         .env("HOME", &paths::home())
+         .env_remove("CARGO_HOME");
         return p;
     }
 
index d46d0d7aec0421621738589f3366e9f6214d4ba7..3d86dcedf89a9f68731529b2ce323b6bbeb0ecad 100644 (file)
@@ -695,3 +695,49 @@ test!(no_rebuild_when_frobbing_default_feature {
     assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
     assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
 });
+
+test!(unions_work_with_no_default_features {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            a = { path = "a" }
+            b = { path = "b" }
+        "#)
+        .file("src/lib.rs", r#"
+            extern crate a;
+            pub fn foo() { a::a(); }
+        "#)
+        .file("b/Cargo.toml", r#"
+            [package]
+            name = "b"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            a = { path = "../a", features = [], default-features = false }
+        "#)
+        .file("b/src/lib.rs", "")
+        .file("a/Cargo.toml", r#"
+            [package]
+            name = "a"
+            version = "0.1.0"
+            authors = []
+
+            [features]
+            default = ["f1"]
+            f1 = []
+        "#)
+        .file("a/src/lib.rs", r#"
+            #[cfg(feature = "f1")]
+            pub fn a() {}
+        "#);
+
+    assert_that(p.cargo_process("build"), execs().with_status(0));
+    assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
+    assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
+});